我曾經在公司後台開發一個儀表板功能,使用者可以拖拉想要的圖表元件,並將元件移動、放大以排版。這個功能有用到 HTML5 的 Drag and Drop API,我們可以使用該 API,輕鬆完成拖曳畫面的元素來重新排序,也能將文件拖至特定區域進行上傳,非常的方便。
今天就跟大家分享這個好玩又有趣的 Drag and Drop API!
Drag and Drop API 可以讓我們定義哪些元素能被拖動,以及我們可在何處放置這些元素。此外還有一些事件,可以監聽控制拖放的過程。
他的優點包括但不限於:
首先,我們先設定一個可以拖動的元素吧!
將元素的 draggable
設為 true
<div id="draggable-item" draggable="true">可以拖動的元素</diV>
dragstart
事件當使用者開始拖動元素後,會觸發 dragstart
事件
const draggableItem = document.getElementById('draggable-item');
draggableItem.addEventListener('dragstart', (event) => {
console.log('e', event)
});
我們就能在網站上按住元素進行拖曳,也能在 console 面板看到相關的資訊
我們可以使用 dataTransfer.setData()
方法儲存當前被拖動元素的 ID,這個資料可以在後續放置元素時使用。
const draggableItem = document.getElementById('draggable-item');
draggableItem.addEventListener('dragstart', (event) => {
event.dataTransfer.setData('text/plain', event.target.id);
});
先建立一個放置區域:
<div id="drop-zone" style="height: 300px; width: 300px; border: 1px solid black">放置區域</div>
然後在 drop
事件中,取得前面儲存的 event.target.id
,藉由這個 id 找到對應的元素,再放到放置區域裡
const dropZone = document.getElementById('drop-zone');
dropZone.addEventListener('dragover', (event) => {
event.preventDefault(); // 阻止默認行為以允許放置
});
dropZone.addEventListener('drop', (event) => {
event.preventDefault();
const draggedItemId = event.dataTransfer.getData('text/plain');
const draggedItem = document.getElementById(draggedItemId);
event.target.appendChild(draggedItem);
});
Drag and Drop API 提供了許多事件,讓我們能夠精確控制拖放的每個過程
事件名稱 | 觸發時機 | 觸發的物件 |
---|---|---|
dragstart |
使用者開始拖曳元素時 | 被拖曳的元素 |
drag |
元素被拖曳時,會持續觸發 | 被拖曳的元素 |
dragenter |
被拖曳的元素進入潛在的放置區域時 | 放置區域 |
dragover |
被拖曳的元素在潛在的放置區域內移動時,會持續觸發 | 放置區域 |
dragleave |
被拖曳的元素離開潛在的放置區域時 | 放置區域 |
drop |
被拖曳的元素在有效的放置區域內被釋放時(例如:放開滑鼠左鍵) | 放置區域 |
dragend |
拖曳操作結束時(無論是否成功放置) | 被拖曳的元素 |
註:
dragover
事件的默認行為。drop
事件只會在有效的放置區域內觸發,即那些在 dragover
事件中調用了 event.preventDefault()
的元素。讓我們來利用這些事件寫兩個放置區域,元素可以在這兩個區域間自由移動,並選擇要放在哪個區域
<div id="draggable-item" draggable="true">可以拖動的元素</div>
<div class="flex">
<div id="drop-zone-1" class="drop-zone">放置區域 1</div>
<div id="drop-zone-2" class="drop-zone">放置區域 2</div>
</div>
const draggableItem = document.getElementById('draggable-item');
const dropZones = document.querySelectorAll('.drop-zone');
const dropZone1 = document.getElementById('drop-zone-1');
const dropZone2 = document.getElementById('drop-zone-2');
dragstart
以及 dragend
讓元素在拖曳狀態下變成半透明,表示這是當前選取的元素draggableItem.addEventListener('dragstart', (event) => {
event.dataTransfer.setData('text/plain', event.target.id);
event.target.style.opacity = '0.5'; // 半透明效果
});
draggableItem.addEventListener('dragend', (event) => {
event.target.style.opacity = ''; // 恢復正常外觀
});
dragover
),以及觸發釋放(drop
)事件時,兩個放置區域會做一樣的事情,可用 forEach
迴圈處理。dropZones.forEach(zone => {
zone.addEventListener('dragover', (event) => {
event.preventDefault(); // 阻止默認行為以允許放置
});
zone.addEventListener('drop', (event) => {
event.preventDefault();
const draggedItemId = event.dataTransfer.getData('text/plain');
const draggedItem = document.getElementById(draggedItemId);
event.target.appendChild(draggedItem);
event.target.classList.remove('drag-over-yellow', 'drag-over-blue');
});
});
當元素進入放置區域時,會偵測進入哪一塊放置區域做對應的樣式,這段也可以寫在 forEach
迴圈內,但為了方便介紹與好理解,我就不寫在迴圈內了。
這邊針對 dropZone1
以及 dropZone2
做了 dragenter
以及 dragleave
兩個事件,將元素移入 / 移出時,會用不同的樣式表示元素進入了該放置區域。
dropZone1.addEventListener('dragenter', (event) => {
event.target.classList.add('drag-over-yellow');
});
dropZone1.addEventListener('dragleave', (event) => {
event.target.classList.remove('drag-over-yellow');
});
dropZone2.addEventListener('dragenter', (event) => {
event.target.classList.add('drag-over-blue');
});
dropZone2.addEventListener('dragleave', (event) => {
event.target.classList.remove('drag-over-blue');
});
.drag-over-yellow {
background-color: yellow;
}
.drag-over-blue {
background-color: teal;
}
.drop-zone {
height: 300px;
width: 300px;
border: 1px solid black;
margin: 10px;
padding: 10px;
}
#draggable-item {
cursor: move;
padding: 10px;
background-color: #f0f0f0;
display: inline-block;
}
.flex {
display: flex;
}
呈現結果如下:
線上範例網址:https://mukiwu.github.io/web-api-demo/drag-and-drop.html
HTML5 的 Drag and Drop API 提供了強大而靈活的工具,我們透過設定可拖動元素、定義拖放區域、處理各種拖放事件,以及自定義視覺效果等技巧,可以大大提升網頁的使用者體驗。文章內容如有任何問題都歡迎留言討論唷!